#pragma once
#ifndef BATTLE_SIMULATOR
#define BATTLE_SIMULATOR

#include <map>
#include <BWAPI.h>
#include <string>
#include "Strategy.h"
#include "StarUtil.h"

//speed at which units approach eachother
#define SPEED 60
//speed at whcih units approach eachother if they hit a block.
//incurred when a melee unit switches targets
#define MELEE_PENALTY 10
//time steps per round
#define BS_TICK 5
//starting range of units
#define BASE_RANGE 500

//Damage types
#define CONCUSSIVE "Concussive" 
#define NORMAL "Normal"
#define EXPLOSIVE "Explosive"

//Unit sizes
#define SMALL "Small"
#define MEDIUM "Medium"
#define LARGE "Large"


//Simulates a battle between two opposing forces.  For labeling purposes, 
//the forces are labeled red and blue.
class BattleSimulator
{

public:

	//****************************************
	//********** LOCAL CLASSES ***************
	//****************************************

	struct UnitStats{
		int nextAttack;
		UnitStats* target;
		bool dead;
		std::string type;
		double shields;
		double hp;
	};

	enum Side{
		RED = 0,  //Player
		BLUE = 1, // computer
	};

	BattleSimulator(Strategy* playerStrat, Strategy* enemyStrat);
	~BattleSimulator(void);
	
	std::map<std::string, std::vector<UnitStats*>*>* getRemainingUnits(
									   bool wantRed);

	//whether or not the player won
	bool redWon(); 
	
	//steps the simulation once
	void step();

	//resolves the simulation or runs 1000 se=teps, whatever happens first
	//warning, will cause game to lag if run on a frame
	void resolve();

	//whether or not the simulation has finished
	bool isDone(); 

	//print the stats of a side
	void printSideStats(bool printRed);

private:

	//****************************************
	//********** ATTRIBUTES ******************
	//****************************************
	std::map<Side, std::map<std::string, std::vector<UnitStats*>*>*> unitStats;
	std::map<Side, Strategy*> strats;
	bool battleOver;
	double totalDamageDealt;
	std::map<Side, std::map<std::string, int>> positions;
	std::map<Side, int> block;
	bool redWonBattle;


	//****************************************
	//********** PRIVATE FUNCTIONS ***********
	//****************************************
	void stepSide(Side side);
	void deleteUnitStats(Side side);
	void checkDead(Side side);
	void setSide(bool isRed);
	void assignTarget(UnitStats* unit, const std::string& targetType,
		const Side& enemy);
	int getRange(Side attacker,const std::string& unit,const std::string& target);
	void advance(Side side,const std::string& type, int limit);
	void BattleSimulator::doAttack(UnitStats* unit);
};

#endif